package com.springboot.killingsystem.access;

import com.alibaba.fastjson.JSON;
import com.springboot.killingsystem.domain.SecondKillingUser;
import com.springboot.killingsystem.redis.AccessKey;
import com.springboot.killingsystem.redis.RedisService;
import com.springboot.killingsystem.result.CodeMsg;
import com.springboot.killingsystem.result.Result;
import com.springboot.killingsystem.service.SecondKillingUserService;
import com.springboot.killingsystem.util.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

@Service
public class AccessIntercept extends HandlerInterceptorAdapter {

    @Autowired
    SecondKillingUserService secondKillingUserService;

    @Autowired
    RedisService redisService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            SecondKillingUser user = getUser(request, response);
            UserContext.setUser(user);

            HandlerMethod handlerMethod = (HandlerMethod) handler;
            AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);
            if (accessLimit == null) {
                // 不做任何限制
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean needLogin = accessLimit.needLogin();
            String key = request.getRequestURI();
            if (needLogin) {
                if (user == null) {
                    render(response, CodeMsg.SESSION_ERROR);
                    return false;
                }
                key += Constant.SPLIT_SIGNAL + user.getId();
            }
            Integer requestTimes = redisService.get(
                    AccessKey.getRequestTimes,
                    key,
                    Integer.class
            );
            AccessKey aK = AccessKey.withExpire(seconds);
            if (requestTimes == null) {
                redisService.set(aK,key,1);
            }else if (requestTimes < maxCount) {
                redisService.incr(aK,key);
            }else {
                render(response, CodeMsg.REQUEST_FREQUENCY);
                return false;
            }
        }

        return true;
    }

    private void render(HttpServletResponse response, CodeMsg cm) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream outputStream = response.getOutputStream();
        String str = JSON.toJSONString(Result.error(cm));
        outputStream.write(str.getBytes(StandardCharsets.UTF_8));
        outputStream.flush(); // 输出数据流
        outputStream.close();
    }

    private SecondKillingUser getUser(
            HttpServletRequest request,
            HttpServletResponse response
    ) {
        String paramToken = request.getParameter(Constant.COOKIE_NAME_TOKEN);
        String cookieToken = getCookieValue(request);
        if (paramToken == null && cookieToken == null) {
            return null;
        }
        String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
        return secondKillingUserService.getByToken(token, response);
    }

    private String getCookieValue(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null || cookies.length <= 0) {
            return null;
        }
        for (Cookie cookie: cookies) {
            if (cookie.getName().equals(Constant.COOKIE_NAME_TOKEN)) {
                return cookie.getValue();
            }
        }
        return null;
    }
}